<?php
/**
 * 自定义进程-基类
*/

namespace houze;

abstract class Process
{
    /**
     * 进程名称
     */
    public $name = 'diy-process';
    
    /**
     * 是否需要while(true) 永久堵塞
    */
    public $onWhile = false;

    /**
     * 等待间隔时间(毫秒)  0不堵塞
    */
    public $sleepS = 0;
    
    /**
     * 当前进程实例
    */
    private $process;
    
    /**
     * 结果存储
    */ 
    public $result = null;
    
    /**
     * 当前连接ID
    */ 
    public $id;

    /**
     * 进程业务入口方法
    */
    abstract public function run();

    /**
     * 业务入口执行前的前置方法
    */
    public function front() {
        return true;
    }

    /**
     * 业务进程发生异常时回调
    */
    public function onException(\Throwable $throwable) 
    {
        // $throwable->getMessage(); 错误内容
        // $throwable->getFile(); 错误文件
        // $throwable->getLine(); 错误行数
    }
    
    /**
     * 连接进程
    */
    public final function start() {
        $this->process = new \Workerman\Connection\AsyncTcpConnection('tcp://127.0.0.1:'.\houze\Config::get('server.task_port'));
        $this->id = $this->process->id;
        $this->process->onConnect = function($connection){
            // 连接成功给连接发送数据
            $connection->send(get_called_class());
        };
        
        // 异步获得结果
        $this->process->onMessage = function($task_connection, $data){
            // 获得结果后记得关闭异步连接
            $this->process->close();
        };
        // 执行异步连接
        $this->process->connect();
    }

    /**
     * 进程逻辑处理
    */
    public final function _callback(){
        try{
            // 先执行前置业务
            $status = $this->front();
            if ($status) {
                // 执行业务代码
                if ($this->onWhile == true) {
                    $this->result = [];
                    while (true) {
                        $this->result[] = $this->run();
                        if ($this->sleepS) {
                            usleep($this->sleepS * 1000);
                        }
                    }
                } else {
                    $this->result = $this->run();
                    if ($this->sleepS) {
                        usleep($this->sleepS * 1000);
                    }
                }
            }
        } catch (\Throwable $throwable) {
            $this->onException($throwable);
        }
    }

    /**
     * 获取进程实例
    */
    public final function getProcess() {
        return $this->process;
    }

    /**
     * 向当前子进程传递数据
    */
    public final static function write($mixed) {
        $process_key = get_called_class();
        return \houze\process\SubProcess::write($process_key, $mixed);
    }
    
    /**
     * 读取结果
    */
    public final function read(){
        $redis = new \houze\Redis();
        $result = $redis->get('task_result');
        
        if(empty($result)) return false;
        $redis->del('task_result');
        $redis->return();
        
        $result = json_decode($result);
        
        return $result;
    }
}